package m_config

import (
	"accx/utils/httpClient"
	"encoding/json"
	"github.com/cihub/seelog"
	"io/ioutil"
	"log"
	"net/http"
	"sync"
	"time"
)

var SysconfigData *Sysconfig
var AccxAndAllaccxData *AccxAndAlllaccx
var MyAccxData *Accx
var config *AppConfig

type Accx struct {
	Group            string             `json:"group"`            //组
	Node             string             `json:"node"`             //节点
	Priority         int                `json:"priority"`         //优先级
	Template         string             `json:"template"`         //使用模板
	OamIp            string             `json:"oamIp"`            //管理IP
	ServiceIp        string             `json:"serviceIp"`        //服务IP
	DataplanIp       string             `json:"dataplanIp"`       //数据面IP
	Gateway          string             `json:"gateway"`          //网关
	PlmnList         []Plmn             `json:"plmnList"`         //PLMN
	NssaiList        []SNssai           `json:"nssaiList"`        //切片
	DnnList          []string           `json:"dnnList"`          //dnn地址列表
	DnnAddress       []UeAddrPoolList   `json:"dnnAddress"`       //继承信息
	StaticIpSegment  []string           `json:"staticIpSegment"`  //静态IP段
	MsisndRange      string             `json:"msisndRange"`      //电话号码段
	Guami            Guami              `json:"guami"`            //guami
	Deviceseq        string             `json:"deviceseq"`        //设备ID
	NfInstanceIds    NfInstanceIds      `json:"nfInstanceIds"`    //实例ID
	Status           string             `json:"status,omitempty"` //状态
	TemporaryService []TemporaryService `json:"temporaryService"` //继承信息
	HeartbeatErrNum  NumAndTime
	ReHeartNum       int
}
type NumAndTime struct {
	Num  int
	Time time.Time
}
type TemporaryService struct {
	Group string `json:"ip"`
	Node  string `json:"port"`
}

type NfInstanceIds struct {
	Amf string `json:"amf "`
	Smf string `json:"smf"`
}
type SNssai struct {
	Sst int    `json:"sst"`
	Sd  string `json:"sd"`
}

type Plmn struct {
	Mcc     string `json:"mcc"`
	Mnc     string `json:"mnc"`
	TacList string `json:"tac_list"`
}

type Guami struct {
	AmfRegionId string `json:"amf_region_id"`
	AmfSetid    string `json:"amf_set_id"`
	AmfPointer  string `json:"amf_pointer"`
}

type UeAddrPoolList struct {
	IpType            string `json:"ipType"`
	Ip                string `json:"ipStart"`
	NetMask           string `json:"netMask"`
	NumberOfAddresses int    `json:"numberOfAddresses"`
}

type AccxAndAlllaccx struct {
	InfoNum         int    `json:"infoNum"`
	Role            string `json:"role"`
	Group           string `json:"group,omitempty"`
	Node            string `json:"node,omitempty"`
	DeviceSeq       string `json:"deviceSeq,omitempty"`
	InheritanceMode bool   `json:"inheritanceMode,omitempty"`
	Accx            []Accx `json:"nodeInfo,omitempty"`
}

func (a *AccxAndAlllaccx) Init(oamip string) {
	if oamip == "" {
		seelog.Error("Oam ip is null:")
		return
	}
	cli := httpClient.NewHttp2Client()
	req, err := http.NewRequest("GET", "http://"+oamip+":9400/coreNetwork/wxCm/roleInfo", nil)
	if err != nil {
		seelog.Error("Oam request is err:", err)
		return
	}
	resp, err := cli.DoRequest(req)
	if err != nil {
		seelog.Error("Oam DoRequest is err:", err)
		return
	}
	defer resp.Body.Close()
	if resp.StatusCode == http.StatusOK {
		respBody, _ := ioutil.ReadAll(resp.Body)
		err := json.Unmarshal(respBody, a)
		if err != nil {
			seelog.Error("AccxAndAlllaccx Unmarshal is err:", err)
			return
		}
	}
	if a.Group == "T1" {
		//TODO:T1
		return
	}
	for i, _ := range a.Accx {
		a.Accx[i].Status = NoConnect
	}
}

func MyaccxInit() {
	for i, _ := range AccxAndAllaccxData.Accx {
		if AccxAndAllaccxData.Accx[i].Node == AccxAndAllaccxData.Node && AccxAndAllaccxData.Accx[i].Deviceseq == AccxAndAllaccxData.DeviceSeq {
			MyAccxData = &AccxAndAllaccxData.Accx[i]
			MyAccxData.Status = Me
			for _, v := range MyAccxData.DnnAddress {
				if v.IpType == "staticIpStart" {
					MyAccxData.StaticIpSegment = append(MyAccxData.StaticIpSegment, v.Ip+"/"+v.NetMask)
				}
			}
			if AccxAndAllaccxData.InheritanceMode == false {
				MyAccxData.Priority = 0
			}
		}
	}
	for i, _ := range SysconfigData.NODELIST {
		if SysconfigData.NODELIST[i].NfType == "SMF" {
			MyAccxData.NfInstanceIds.Smf = SysconfigData.NODELIST[i].NfInstanceId
		}
		if SysconfigData.NODELIST[i].NfType == "AMF" {
			MyAccxData.NfInstanceIds.Amf = SysconfigData.NODELIST[i].NfInstanceId
		}
	}
}

// all sysconfig
type Sysconfig struct {
	SUBSDB             Subsdb   `json:"SUBSDB"`
	SERVERS            Services `json:"SERVERS"`
	PROTOCOL           string   `json:"PROTOCOL"`
	NODELIST           []Node   `json:"NODE_LIST"`
	SERVICEINTERFACEIP []string `json:"SERVICE_INTERFACE_IP",omitempty`
}

type Subsdb struct {
	REDISSENTINELMASTER string `json:"REDIS_SENTINEL_MASTER",omitempty`
	REDISSERVERIP       string `json:"REDIS_SERVER_IP",omitempty`
	REDISPASSWORD       string `json:"REDIS_PASSWORD",omitempty`
	REDISSENTINELIP     string `json:"REDIS_SENTINEL_IP",omitempty`
	DBSERVERIP          string `json:"DB_SERVER_IP",omitempty`
	DBUSERNAME          string `json:"DB_USERNAME",omitempty`
	DBPASSWORD          string `json:"DB_PASSWORD",omitempty`
}

type Services struct {
	CMIP            string `json:"CM_IP"`
	PMIP            string `json:"PM_IP"`
	FMIP            string `json:"FM_IP"`
	OMCIP           string `json:"OMC_IP"`
	OAMIP           string `json:"OAM_IP"`
	SYSIP           string `json:"SYS_IP"`
	ZOOKEEPERIP     string `json:"ZOOKEEPER_IP"`
	LICENSESERVERIP string `json:"LICENSE_SERVER_IP"`
	REDISSERVERIP   string `json:"REDIS_SERVER_IP"`
	REDISPASSWORD   string `json:"REDIS_PASSWORD"`
	DBSERVERIP      string `json:"DB_SERVER_IP"`
	DBUSERNAME      string `json:"DB_USERNAME"`
	DBPASSWORD      string `json:"DB_PASSWORD"`
}

type Node struct {
	LicenseId    int    `json:"LICENSE_ID",omitempty`
	NfId         string `json:"NF_ID",omitempty`
	NfInstanceId string `json:"NF_INSTANCEID",omitempty`
	NfType       string `json:"TYPE",omitempty`
}

func (s *Sysconfig) Init(sysconfigfilePath string) {
	data, err := ioutil.ReadFile(sysconfigfilePath)
	if err != nil {
		log.Fatalln("Load sysconfigfile error:", err)
	}
	err = json.Unmarshal(data, s)
	if err != nil {
		log.Fatal("App m_config is invalid! err:", err)
	}
}

type ServerConfig struct {
	Name         string `json:"name"`
	IP           string `json:"ip"`
	Port         string `json:"port"`
	ReadTimeout  uint   `json:"readTimeout"`
	WriteTimeout uint   `json:"writeTimeout"`
}

type AppConfig struct {
	Server            []ServerConfig `json:"servers"`
	MySqlHost         string         `json:"mysqlHost"`
	MySqlDb           string         `json:"mysqlDb"`
	MySqlUser         string         `json:"mysqlUser"`
	MySqlPassword     string         `json:"mysqlPassword"`
	LogConfigPath     string         `json:"logConfigPath"`
	HttpAccessLogPath string         `json:"httpAccessLogPath"`
}

func initConfig() {
	config = &AppConfig{
		Server:            []ServerConfig{{IP: "0.0.0.0", Port: "2333", ReadTimeout: 10, WriteTimeout: 10}, {IP: "0.0.0.0", Port: "2444", ReadTimeout: 10, WriteTimeout: 10}},
		MySqlHost:         "127.0.0.1",
		MySqlDb:           "accx_db",
		MySqlUser:         "root",
		MySqlPassword:     "123456",
		LogConfigPath:     "./config/accxLogConfig.xml",
		HttpAccessLogPath: "/var/log/accx/gin.log",
	}
}

func (config *AppConfig) LoadConfig(configPath string) {
	data, err := ioutil.ReadFile(configPath)
	if err != nil {
		log.Fatalln("Load app m_config error:", err)
	}
	err = json.Unmarshal(data, config)
	if err != nil {
		log.Fatal("App m_config is invalid! err:", err)
	}
	for i, _ := range config.Server {
		config.Server[i].IP = MyAccxData.ServiceIp
	}
}

var once sync.Once

func NewAccxAndAllaccxData() *AccxAndAlllaccx {
	AccxAndAllaccxData = new(AccxAndAlllaccx)
	return AccxAndAllaccxData
}
func NewSysconfigData() *Sysconfig {
	SysconfigData = new(Sysconfig)
	return SysconfigData
}
func GetConfigInstance() *AppConfig {
	once.Do(initConfig)
	return config
}
